from typing import Dict, Any, Optional
import snap7
from utils import PLCDataType, DataBlockVariable
from datetime import datetime
from plc_config import DATA_BLOCK_VARIABLES

import struct



class PLCClient:
    """
    PLC客户端类，使用S7协议连接西门子PLC
    """
    
    def __init__(self, config: Dict[str, Any]):
        self.config = config
        self.host = config["host"]
        self.timeout = config["timeout"]
        
        # S7协议相关
        self.rack = config.get("rack", 0)
        self.slot = config.get("slot", 1)
        self.s7_client = None
        
        self.connected = False
        self.last_data: Dict[str, Any] = {}
    
    def connect(self) -> bool:
        """连接到PLC"""
        try:
            return self._connect_s7()
        except Exception as e:
            print(f"❌ 连接PLC异常: {e}")
            self.connected = False
            return False
    
    def _connect_s7(self) -> bool:

        try:
            self.s7_client = snap7.client.Client()
            self.s7_client.connect(self.host, self.rack, self.slot)
            self.connected = True
            print(f"✅ 成功连接到PLC (S7协议): {self.host} Rack:{self.rack} Slot:{self.slot}")
            return True
        except Exception as e:
            print(f"❌ S7协议连接失败: {e}")
            self.connected = False
            return False
        
    def disconnect(self):
        """断开PLC连接"""
        try:
            if self.s7_client:
                self.s7_client.disconnect()
                print("🔌 已断开S7连接")
            self.connected = False
        except Exception as e:
            print(f"⚠️ 断开连接时发生异常: {e}")
            self.connected = False
    
    def read_data_block_variable(self, variable: DataBlockVariable) -> Optional[Any]:
        """读取数据块变量"""
        if not self.connected:
            return None
        
        return self._read_s7_variable(variable)
    
    def _read_s7_variable(self, variable: DataBlockVariable) -> Optional[Any]:
        """使用S7协议读取变量"""
        if not self.s7_client:
            return None
        
        try:
            # 根据数据类型确定读取长度
            if variable.data_type == PLCDataType.BOOL:
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 1)
                if data:
                    byte_val = data[0]
                    return bool(byte_val & (1 << variable.bit_offset))
            elif variable.data_type in [PLCDataType.BYTE, PLCDataType.USINT, PLCDataType.CHAR]:
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 1)
                return data[0] if data else None
            elif variable.data_type == PLCDataType.SINT:
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 1)
                if data:
                    value = data[0]
                    # SINT类型处理符号位 (-128 to 127)
                    if value > 127:
                        value -= 256
                    return value
            elif variable.data_type in [PLCDataType.WORD, PLCDataType.UINT, PLCDataType.WCHAR]:
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 2)
                if data and len(data) >= 2:
                    # 大端序转换
                    value = (data[0] << 8) | data[1]
                    return value
            elif variable.data_type == PLCDataType.INT:
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 2)
                if data and len(data) >= 2:
                    # 大端序转换
                    value = (data[0] << 8) | data[1]
                    # INT类型需要处理符号位
                    if value > 32767:
                        value -= 65536
                    return value
            elif variable.data_type in [PLCDataType.DWORD, PLCDataType.UDINT]:
                # 读取32位无符号数据
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 4)
                if data and len(data) >= 4:
                    # 大端序转换
                    value = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]
                    return value
            elif variable.data_type == PLCDataType.DINT:
                # 读取32位有符号数据
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 4)
                if data and len(data) >= 4:
                    # 大端序转换
                    value = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]
                    # DINT类型需要处理符号位
                    if value > 2147483647:
                        value -= 4294967296
                    return value
            elif variable.data_type in [PLCDataType.LWORD, PLCDataType.ULINT]:
                # 读取64位无符号数据
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 8)
                if data and len(data) >= 8:
                    # 大端序转换
                    value = 0
                    for i in range(8):
                        value = (value << 8) | data[i]
                    return value
            elif variable.data_type == PLCDataType.LINT:
                # 读取64位有符号数据
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 8)
                if data and len(data) >= 8:
                    # 大端序转换
                    value = 0
                    for i in range(8):
                        value = (value << 8) | data[i]
                    # LINT类型需要处理符号位
                    if value > 9223372036854775807:
                        value -= 18446744073709551616
                    return value
            elif variable.data_type == PLCDataType.REAL:
                # 读取32位浮点数
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 4)
                if data and len(data) >= 4:
                    bytes_data = bytes(data)
                    return struct.unpack('>f', bytes_data)[0]
            elif variable.data_type == PLCDataType.LREAL:
                # 读取64位浮点数
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 8)
                if data and len(data) >= 8:
                    bytes_data = bytes(data)
                    return struct.unpack('>d', bytes_data)[0]
            elif variable.data_type in [PLCDataType.TIME, PLCDataType.S5TIME, PLCDataType.DATE, 
                                       PLCDataType.TIME_OF_DAY, PLCDataType.TOD]:
                # 时间类型通常为32位
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 4)
                if data and len(data) >= 4:
                    value = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]
                    return value
            elif variable.data_type in [PLCDataType.LTIME, PLCDataType.DATE_AND_TIME, PLCDataType.DT]:
                # 长时间类型为64位
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 8)
                if data and len(data) >= 8:
                    value = 0
                    for i in range(8):
                        value = (value << 8) | data[i]
                    return value
            elif variable.data_type in [PLCDataType.COUNTER, PLCDataType.TIMER]:
                # 计数器和定时器通常为16位
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 2)
                if data and len(data) >= 2:
                    value = (data[0] << 8) | data[1]
                    return value
            elif variable.data_type == PLCDataType.STRING:
                # 读取字符串，前2字节为长度信息
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 256)
                if data and len(data) >= 2:
                    max_len = data[0]
                    actual_len = data[1]
                    if actual_len > 0 and len(data) >= 2 + actual_len:
                        string_bytes = data[2:2+actual_len]
                        return string_bytes.decode('utf-8', errors='ignore')
                    return ""
            elif variable.data_type == PLCDataType.WSTRING:
                # 读取宽字符串，前4字节为长度信息（大端序）
                data = self.s7_client.db_read(variable.db_number, variable.start_offset, 512)
                if data and len(data) >= 4:
                    # 前2字节：最大长度（字符数）
                    max_len = (data[0] << 8) | data[1]
                    # 后2字节：实际长度（字符数）
                    actual_len = (data[2] << 8) | data[3]
                    if actual_len > 0 and len(data) >= 4 + actual_len * 2:
                        # WSTRING使用UTF-16BE编码，每个字符占2字节
                        string_bytes = data[4:4+actual_len*2]
                        return string_bytes.decode('utf-16be', errors='ignore')
                    return ""
                
            return None
        except Exception as e:
            print(f"❌ S7读取变量{variable.name}失败: {e}")
            return None
    
    def write_data_block_variable(self, variable: DataBlockVariable, value: Any) -> bool:
        """写入数据块变量"""
        if not self.connected:
            return False
        
        return self._write_s7_variable(variable, value)
    
    def _write_s7_variable(self, variable: DataBlockVariable, value: Any) -> bool:
        """使用S7协议写入变量"""
        if not self.s7_client:
            return False
        
        try:
            # 根据数据类型进行写入
            if variable.data_type == PLCDataType.BOOL:
                # 先读取当前字节值
                current_data = self.s7_client.db_read(variable.db_number, variable.start_offset, 1)
                if current_data:
                    byte_val = current_data[0]
                    if value:
                        # 设置指定位为1
                        byte_val |= (1 << variable.bit_offset)
                    else:
                        # 设置指定位为0
                        byte_val &= ~(1 << variable.bit_offset)
                    
                    # 写回修改后的字节
                    data = bytearray([byte_val])
                    self.s7_client.db_write(variable.db_number, variable.start_offset, data)
                    return True
                    
            elif variable.data_type in [PLCDataType.BYTE, PLCDataType.USINT, PLCDataType.CHAR]:
                data = bytearray([int(value) & 0xFF])
                self.s7_client.db_write(variable.db_number, variable.start_offset, data)
                return True
                
            elif variable.data_type == PLCDataType.SINT:
                int_val = int(value)
                # SINT类型处理负数 (-128 to 127)
                if int_val < 0:
                    int_val += 256
                data = bytearray([int_val & 0xFF])
                self.s7_client.db_write(variable.db_number, variable.start_offset, data)
                return True
                
            elif variable.data_type in [PLCDataType.WORD, PLCDataType.UINT, PLCDataType.WCHAR]:
                int_val = int(value) & 0xFFFF
                # 大端序转换
                data = bytearray([(int_val >> 8) & 0xFF, int_val & 0xFF])
                self.s7_client.db_write(variable.db_number, variable.start_offset, data)
                return True
                
            elif variable.data_type == PLCDataType.INT:
                int_val = int(value)
                # INT类型处理负数
                if int_val < 0:
                    int_val += 65536
                # 大端序转换
                data = bytearray([(int_val >> 8) & 0xFF, int_val & 0xFF])
                self.s7_client.db_write(variable.db_number, variable.start_offset, data)
                return True
                
            elif variable.data_type in [PLCDataType.DWORD, PLCDataType.UDINT]:
                int_val = int(value) & 0xFFFFFFFF
                # 大端序转换
                data = bytearray([
                    (int_val >> 24) & 0xFF,
                    (int_val >> 16) & 0xFF,
                    (int_val >> 8) & 0xFF,
                    int_val & 0xFF
                ])
                self.s7_client.db_write(variable.db_number, variable.start_offset, data)
                return True
                
            elif variable.data_type == PLCDataType.DINT:
                int_val = int(value)
                # DINT类型处理负数
                if int_val < 0:
                    int_val += 4294967296
                # 大端序转换
                data = bytearray([
                    (int_val >> 24) & 0xFF,
                    (int_val >> 16) & 0xFF,
                    (int_val >> 8) & 0xFF,
                    int_val & 0xFF
                ])
                self.s7_client.db_write(variable.db_number, variable.start_offset, data)
                return True
                
            elif variable.data_type in [PLCDataType.LWORD, PLCDataType.ULINT]:
                int_val = int(value) & 0xFFFFFFFFFFFFFFFF
                # 大端序转换64位
                data = bytearray()
                for i in range(8):
                    data.append((int_val >> (56 - i * 8)) & 0xFF)
                self.s7_client.db_write(variable.db_number, variable.start_offset, data)
                return True
                
            elif variable.data_type == PLCDataType.LINT:
                int_val = int(value)
                # LINT类型处理负数
                if int_val < 0:
                    int_val += 18446744073709551616
                # 大端序转换64位
                data = bytearray()
                for i in range(8):
                    data.append((int_val >> (56 - i * 8)) & 0xFF)
                self.s7_client.db_write(variable.db_number, variable.start_offset, data)
                return True
                
            elif variable.data_type == PLCDataType.REAL:
                # 写入32位浮点数
                float_val = float(value)
                packed_data = struct.pack('>f', float_val)
                self.s7_client.db_write(variable.db_number, variable.start_offset, packed_data)
                return True
                
            elif variable.data_type == PLCDataType.LREAL:
                # 写入64位浮点数
                float_val = float(value)
                packed_data = struct.pack('>d', float_val)
                self.s7_client.db_write(variable.db_number, variable.start_offset, packed_data)
                return True
                
            elif variable.data_type in [PLCDataType.TIME, PLCDataType.S5TIME, PLCDataType.DATE, 
                                       PLCDataType.TIME_OF_DAY, PLCDataType.TOD]:
                # 时间类型通常为32位
                int_val = int(value) & 0xFFFFFFFF
                data = bytearray([
                    (int_val >> 24) & 0xFF,
                    (int_val >> 16) & 0xFF,
                    (int_val >> 8) & 0xFF,
                    int_val & 0xFF
                ])
                self.s7_client.db_write(variable.db_number, variable.start_offset, data)
                return True
                
            elif variable.data_type in [PLCDataType.LTIME, PLCDataType.DATE_AND_TIME, PLCDataType.DT]:
                # 长时间类型为64位
                int_val = int(value) & 0xFFFFFFFFFFFFFFFF
                data = bytearray()
                for i in range(8):
                    data.append((int_val >> (56 - i * 8)) & 0xFF)
                self.s7_client.db_write(variable.db_number, variable.start_offset, data)
                return True
                
            elif variable.data_type in [PLCDataType.COUNTER, PLCDataType.TIMER]:
                # 计数器和定时器通常为16位
                int_val = int(value) & 0xFFFF
                data = bytearray([(int_val >> 8) & 0xFF, int_val & 0xFF])
                self.s7_client.db_write(variable.db_number, variable.start_offset, data)
                return True
                
            elif variable.data_type == PLCDataType.STRING:
                # 写入字符串
                str_val = str(value)
                str_bytes = str_val.encode('utf-8')
                # 限制字符串长度
                max_len = 254  # PLC STRING最大长度通常为254
                if len(str_bytes) > max_len:
                    str_bytes = str_bytes[:max_len]
                
                # 构造STRING格式：[最大长度][实际长度][字符串内容]
                data = bytearray([max_len, len(str_bytes)] + list(str_bytes))
                # 填充到256字节
                while len(data) < 256:
                    data.append(0)
                
                self.s7_client.db_write(variable.db_number, variable.start_offset, data)
                return True
                
            elif variable.data_type == PLCDataType.WSTRING:
                # 写入宽字符串
                str_val = str(value)
                str_bytes = str_val.encode('utf-16be')
                # 限制字符串长度（字符数）
                max_len = 254  # WSTRING最大字符数
                char_count = len(str_val)
                if char_count > max_len:
                    str_val = str_val[:max_len]
                    str_bytes = str_val.encode('utf-16be')
                    char_count = max_len
                
                # 构造WSTRING格式：[最大长度2字节][实际长度2字节][字符串内容]
                data = bytearray()
                data.extend([(max_len >> 8) & 0xFF, max_len & 0xFF])  # 最大长度
                data.extend([(char_count >> 8) & 0xFF, char_count & 0xFF])  # 实际长度
                data.extend(str_bytes)  # 字符串内容
                
                # 填充到512字节
                while len(data) < 512:
                    data.append(0)
                
                self.s7_client.db_write(variable.db_number, variable.start_offset, data)
                return True
                
            return False
        except Exception as e:
            print(f"❌ S7写入变量{variable.name}失败: {e}")
            return False
    

    
    def read_all_variables(self, variables_config: Dict[str, DataBlockVariable]) -> Dict[str, Any]:
        """读取所有配置的变量，返回简化的键值对结构"""
        data = {}
        for var_key, variable in variables_config.items():
            value = self.read_data_block_variable(variable)
            data[var_key] = value
        
        self.last_data = data
        return data
    
    def get_variable_info(self, var_key: str, variables_config: Dict[str, DataBlockVariable]) -> Optional[DataBlockVariable]:
        """获取指定变量的详细信息"""
        return variables_config.get(var_key)
    
    def get_all_variables_info(self, variables_config: Dict[str, DataBlockVariable]) -> Dict[str, DataBlockVariable]:
        """获取所有变量的详细信息"""
        return variables_config.copy()
    
    def clear_all_variables(self, variables_config: Dict[str, DataBlockVariable]) -> Dict[str, bool]:
        """清空所有配置变量，将它们设置为默认的零值"""
        results = {}
        
        if not self.connected:
            print("❌ PLC未连接，无法清空变量")
            return results
        
        print("🧹 开始清空所有PLC变量...")
        
        for var_key, variable in variables_config.items():
            try:
                # 根据数据类型设置默认零值
                if variable.data_type == PLCDataType.BOOL:
                    zero_value = False
                elif variable.data_type in [PLCDataType.BYTE, PLCDataType.WORD, PLCDataType.INT, 
                                          PLCDataType.DWORD, PLCDataType.DINT]:
                    zero_value = 0
                elif variable.data_type == PLCDataType.REAL:
                    zero_value = 0.0
                elif variable.data_type in [PLCDataType.STRING, PLCDataType.WSTRING]:
                    zero_value = ""
                else:
                    print(f"⚠️ 跳过未知数据类型的变量: {var_key}")
                    results[var_key] = False
                    continue
                
                # 写入零值
                success = self.write_data_block_variable(variable, zero_value)
                results[var_key] = success
                
                if success:
                    print(f"✅ 已清空变量 {var_key} ({variable.name})")
                else:
                    print(f"❌ 清空变量失败 {var_key} ({variable.name})")
                    
            except Exception as e:
                print(f"❌ 清空变量 {var_key} 时发生异常: {e}")
                results[var_key] = False
        
        success_count = sum(1 for success in results.values() if success)
        total_count = len(results)
        print(f"🧹 变量清空完成: {success_count}/{total_count} 个变量成功清空")
        
        return results
    
# 根据plc_config中字段从plc读取并打印
def read_and_print_all_plc_data(plc_client: PLCClient, variables_config: Dict[str, DataBlockVariable]):
    def get_display_width(text: str) -> int:
        """计算字符串的显示宽度，中文字符占2个位置，英文字符占1个位置"""
        width = 0
        for char in text:
            if ord(char) > 127:  # 非ASCII字符（包括中文）
                width += 2
            else:
                width += 1
        return width

    def pad_string(text: str, target_width: int) -> str:
        """根据显示宽度填充字符串"""
        current_width = get_display_width(text)
        if current_width >= target_width:
            return text
        padding = target_width - current_width
        return text + ' ' * padding

    def format_variable_info(var_key: str, variable: DataBlockVariable, value: Any) -> str:
        """格式化数据块变量信息显示"""
        # 处理None值的情况
        if value is None:
            value_display = "N/A"
        else:
            value_display = str(value)
        
        # 格式化值字符串
        if variable.unit and value is not None:
            value_str = f"{value_display} {variable.unit}"
        else:
            value_str = value_display
        
        # 使用智能对齐，考虑中文字符宽度
        var_key_padded = pad_string(var_key, 26)
        var_name_padded = pad_string(variable.name, 20)
        value_str_padded = pad_string(value_str, 18)
        address_padded = pad_string(variable.get_address_string(), 15)
        
        return f"{var_key_padded} | {var_name_padded} | {value_str_padded} | {address_padded} | {variable.description}"
    
    
    """从PLC读取所有配置的变量值并打印"""
    
    if not plc_client:
        print("❌ PLC客户端未初始化")
        return
    
    if not plc_client.connected:
        print("❌ PLC未连接，尝试重新连接...")
        if not plc_client.connect():
            print("❌ PLC连接失败")
            return
    
    print("📊 正在读取PLC数据...")
    print("=" * 120)
    # 使用智能对齐的表头
    header_var_key = pad_string("变量键", 26)
    header_var_name = pad_string("变量名", 20)
    header_value = pad_string("值", 18)
    header_address = pad_string("地址", 15)
    print(f"{header_var_key} | {header_var_name} | {header_value} | {header_address} | 描述")
    print("-" * 120)
    
    try:
        # 读取所有变量数据
        variable_data = plc_client.read_all_variables(variables_config)
        
        for var_key, value in variable_data.items():
            # 获取变量的详细信息
            variable = plc_client.get_variable_info(var_key, variables_config)
            if variable:
                # 格式化并打印变量信息
                print(format_variable_info(var_key, variable, value))
        
        print("-" * 110)
        print(f"✅ 成功读取 {len(variable_data)} 个变量")
        print(f"📅 读取时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        
    except Exception as e:
        print(f"❌ 读取PLC数据失败: {e}")
    
    print("=" * 120)


if __name__ == "__main__":
    # 测试PLC客户端
    print("🚀 开始测试PLC客户端...")
    
    # PLC配置
    plc_config = {
        "host": "192.168.0.10",  # 请根据实际PLC IP地址修改
        "timeout": 5,
        "rack": 0,
        "slot": 1
    }
    
    # 创建PLC客户端实例
    plc_client = PLCClient(plc_config)
    
    try:
        # 尝试连接PLC
        print(f"🔗 尝试连接PLC: {plc_config['host']}")
        if plc_client.connect():
            print("✅ PLC连接成功！")
            
            # 读取并打印所有PLC数据
            read_and_print_all_plc_data(plc_client, DATA_BLOCK_VARIABLES)
            
        else:
            print("❌ PLC连接失败，请检查：")
            print("   1. PLC IP地址是否正确")
            print("   2. 网络连接是否正常")
            print("   3. PLC是否在运行状态")
            print("   4. Rack和Slot配置是否正确")
            
    except KeyboardInterrupt:
        print("\n⚠️ 用户中断测试")
    except Exception as e:
        print(f"❌ 测试过程中发生异常: {e}")
    finally:
        # 在断开连接前，清空所有变量并重新读取
        if plc_client.connected:
            print("\n" + "="*60)
            print("🧹 测试结束前清空所有变量...")
            
            # 清空所有变量
            clear_results = plc_client.clear_all_variables(DATA_BLOCK_VARIABLES)
            
            # 等待一下让PLC处理写入操作
            import time
            time.sleep(1)
            
            print("\n📊 清空后重新读取所有变量...")
            print("="*120)
            
            # 重新读取并显示所有变量
            read_and_print_all_plc_data(plc_client, DATA_BLOCK_VARIABLES)
            
            # 断开连接
            plc_client.disconnect()
        print("🏁 测试结束")


      
def get_sim_plc_data():
    """模拟PLC数据函数，当SIM=True时使用"""
    # 模拟数据，使用更新后的变量名
    sim_data = {
        "Motor_id": {
            "name": "电机序号",
            "value": "MT2024001",
            "data_type": "STRING",
            "unit": "",
            "description": "电机序号",
            "address": "DB1.DBB0",
            "db_number": 1,
            "start_offset": 0,
            "bit_offset": None
        },
        "EDCU_id": {
            "name": "门控器序号",
            "value": "EDCU2024001",
            "data_type": "STRING",
            "unit": "",
            "description": "门控器序号",
            "address": "DB1.DBB256",
            "db_number": 1,
            "start_offset": 256,
            "bit_offset": None
        },
        "Wiring_barcode": {
            "name": "线束条码",
            "value": "WB2024001",
            "data_type": "STRING",
            "unit": "",
            "description": "线束条码",
            "address": "DB1.DBB512",
            "db_number": 1,
            "start_offset": 512,
            "bit_offset": None
        },
        "Screw_assembly": {
            "name": "螺杆装配",
            "value": True,
            "data_type": "BOOL",
            "unit": "",
            "description": "螺杆装配完成标志",
            "address": "DB1.DBX768.0",
            "db_number": 1,
            "start_offset": 768,
            "bit_offset": 0
        },
        "Dielectric_test": {
            "name": "耐压测试",
            "value": True,
            "data_type": "BOOL",
            "unit": "",
            "description": "耐压测试结果",
            "address": "DB1.DBX768.1",
            "db_number": 1,
            "start_offset": 768,
            "bit_offset": 1
        },
        "Obstacle_test": {
            "name": "防夹测试",
            "value": True,
            "data_type": "BOOL",
            "unit": "",
            "description": "防夹测试结果",
            "address": "DB1.DBX768.2",
            "db_number": 1,
            "start_offset": 768,
            "bit_offset": 2
        },
        "Grider_assembly": {
            "name": "横梁装配",
            "value": True,
            "data_type": "BOOL",
            "unit": "",
            "description": "横梁装配完成标志",
            "address": "DB1.DBX768.3",
            "db_number": 1,
            "start_offset": 768,
            "bit_offset": 3
        },
        "Open_time": {
            "name": "开门时间",
            "value": 2.5,
            "data_type": "REAL",
            "unit": "s",
            "description": "开门所用时间",
            "address": "DB1.DBD770",
            "db_number": 1,
            "start_offset": 770,
            "bit_offset": None
        },
        "Push_force": {
            "name": "推力测试",
            "value": 150.5,
            "data_type": "REAL",
            "unit": "N",
            "description": "推力测试结果",
            "address": "DB1.DBD774",
            "db_number": 1,
            "start_offset": 774,
            "bit_offset": None
        },
        "Bracket_assembly_wiring": {
            "name": "支架装配机构布线",
            "value": True,
            "data_type": "BOOL",
            "unit": "",
            "description": "支架装配机构布线完成标志",
            "address": "DB1.DBX778.0",
            "db_number": 1,
            "start_offset": 778,
            "bit_offset": 0
        },
        "Close_time": {
            "name": "关门时间",
            "value": 3.2,
            "data_type": "REAL",
            "unit": "s",
            "description": "关门所用时间",
            "address": "DB1.DBD780",
            "db_number": 1,
            "start_offset": 780,
            "bit_offset": None
        },
        "Pull_force": {
            "name": "拉力测试",
            "value": 120.8,
            "data_type": "REAL",
            "unit": "N",
            "description": "拉力测试结果",
            "address": "DB1.DBD784",
            "db_number": 1,
            "start_offset": 784,
            "bit_offset": None
        },
        
        "project_name": {
            "name": "项目名称",
            "value": "智能门控系统",
            "data_type": "STRING",
            "unit": "",
            "description": "项目名称",
            "address": "DB2.DBB256",
            "db_number": 2,
            "start_offset": 0,
            "bit_offset": None
        },
        "product_number": {
            "name": "产品编号",
            "value": "PDT-2024-001",
            "data_type": "STRING",
            "unit": "",
            "description": "产品编号",
            "address": "DB2.DBB512",
            "db_number": 2,
            "start_offset": 256,
            "bit_offset": None
        },
        "station_name": {
            "name": "工位名称",
            "value": "装配工位01",
            "data_type": "STRING",
            "unit": "",
            "description": "工位名称",
            "address": "DB2.DBB0",
            "db_number": 2,
            "start_offset": 512,
            "bit_offset": None
        },
        "count": {
            "name": "列数",
            "value": "TT5",
            "data_type": "STRING",
            "unit": "",
            "description": "列数",
            "address": "DB2.DBB768",
            "db_number": 2,
            "start_offset": 768,
            "bit_offset": None
        },
        "trace_barcode": {
            "name": "追溯条码",
            "value": "TR2024001",
            "data_type": "STRING",
            "unit": "",
            "description": "追溯条码",
            "address": "DB2.DBB1024",
            "db_number": 2,
            "start_offset": 1024,
            "bit_offset": None
        },
        "operator": {
            "name": "操作人员",
            "value": "陈工",
            "data_type": "WSTRING",
            "unit": "",
            "description": "操作人员",
            "address": "DB2.DBB1280",
            "db_number": 2,
            "start_offset": 1280,
            "bit_offset": None
        },
        "rtp_version": {
            "name": "RTP版本",
            "value": "v2.1.0",
            "data_type": "STRING",
            "unit": "",
            "description": "RTP版本号",
            "address": "DB2.DBB1792",
            "db_number": 2,
            "start_offset": 1792,
            "bit_offset": None
        },
        "software_version": {
            "name": "软件版本",
            "value": "v1.5.2",
            "data_type": "STRING",
            "unit": "",
            "description": "软件版本号",
            "address": "DB2.DBB2048",
            "db_number": 2,
            "start_offset": 2048,
            "bit_offset": None
        },
        "product_status": {
            "name": "产品状态",
            "value": "合格",
            "data_type": "STRING",
            "unit": "",
            "description": "产品状态",
            "address": "DB2.DBB2304",
            "db_number": 2,
            "start_offset": 2304,
            "bit_offset": None
        },
        "qualified_count": {
            "name": "合格品统计",
            "value": "98/98",
            "data_type": "STRING",
            "unit": "",
            "description": "合格品统计",
            "address": "DB2.DBB2560",
            "db_number": 2,
            "start_offset": 2560,
            "bit_offset": None
        },
        "unqualified_count": {
            "name": "不良品统计",
            "value": 2,
            "data_type": "DINT",
            "unit": "",
            "description": "不良品统计",
            "address": "DB2.DBD2816",
            "db_number": 2,
            "start_offset": 2816,
            "bit_offset": None
        },
        "concession_count": {
            "name": "让步放行统计",
            "value": "1/24",
            "data_type": "STRING",
            "unit": "",
            "description": "让步放行统计",
            "address": "DB2.DBB2820",
            "db_number": 2,
            "start_offset": 2820,
            "bit_offset": None
        }
    }
    
    return {
        "timestamp": datetime.now().isoformat(),
        "protocol": "S7",
        "data": sim_data,
        "status": "success"
    }